<template>
  <el-space v-if="readonly" class="itemNames">
    <span v-for="i in names" :key="i">{{ i }}</span>
  </el-space>
  <el-select
    v-else-if="props.mode == 'select'"
    v-model="inputVal"
    :disabled="props.disabled"
    :placeholder="props.placeholder"
    :style="$attrs.style"
    :clearable="props.clearable"
    :class="$attrs.class"
    :multiple="props.multiple"
    @change="chooseChange"
  >
    <el-option
      v-for="item in items"
      :key="item.DicValue"
      :label="item.DicText"
      :value="item.DicValue"
    />
  </el-select>
  <el-checkbox-group
    v-else-if="props.mode == 'checkbox' && props.multiple"
    v-model="inputVal"
    :disabled="props.disabled"
    @change="chooseChange"
  >
    <el-checkbox v-for="item in items" :key="item.DicValue" :label="item.DicValue">{{
      item.DicText
    }}</el-checkbox>
  </el-checkbox-group>
  <el-checkbox-group
    v-else-if="props.mode == 'checkbox' && props.multiple == false"
    v-model="inputVal"
    :disabled="props.disabled"
    :max="1"
    @change="chooseChange"
  >
    <el-checkbox v-for="item in items" :key="item.DicValue" :label="item.DicValue">{{
      item.DicText
    }}</el-checkbox>
  </el-checkbox-group>
  <el-checkbox-group
    v-else-if="props.mode == 'button' && props.multiple"
    v-model="inputVal"
    :disabled="props.disabled"
    @change="chooseChange"
  >
    <el-checkbox-button v-for="item in items" :key="item.DicValue" :label="item.DicValue">{{
      item.DicText
    }}</el-checkbox-button>
  </el-checkbox-group>
  <el-radio-group
    v-else-if="props.mode == 'radio'"
    v-model="inputVal"
    :disabled="props.disabled"
    @input="chooseChange"
  >
    <el-radio v-for="item in items" :key="item.DicValue" :label="item.DicValue">{{
      item.DicText
    }}</el-radio>
  </el-radio-group>
  <el-radio-group v-else v-model="inputVal" :disabled="props.disabled" @input="chooseChange">
    <el-radio-button v-for="item in items" :key="item.DicValue" :label="item.DicValue">{{
      item.DicText
    }}</el-radio-button>
  </el-radio-group>
</template>

<script setup lang="ts">
import { gets, GetDicTextList } from '@/api/base/dictItem'
import { dicItemModel } from '@/api/types/dictType'
import { joinStr } from '@/utils'
import { propTypes } from '@/utils/propTypes'
import { ref, unref, watch } from 'vue'

const items = ref<dicItemModel[]>([])
const inputVal = ref<string | null | Array<string>>(null)
const emit = defineEmits(['change', 'update:modelValue'])
const props = defineProps({
  dicId: propTypes.string,
  clearable: propTypes.bool.def(false),
  disabled: propTypes.bool.def(false),
  modelValue: propTypes.any,
  labelField: propTypes.string,
  source: propTypes.object,
  placeholder: propTypes.string.def('选择字典'),
  filterFunc: propTypes.func,
  mode: propTypes.string.def('select'),
  multiple: propTypes.bool,
  readonly: propTypes.bool
})
const names = ref<string[]>([])
const resetValue = (val) => {
  if (val == null) {
    inputVal.value =
      props.multiple || (props.mode === 'button' && props.multiple) || props.mode === 'checkbox'
        ? []
        : null
  } else if (
    props.multiple ||
    (props.mode === 'button' && props.multiple) ||
    props.mode === 'checkbox'
  ) {
    inputVal.value = Array.isArray(val) ? val : [val]
  } else if (Array.isArray(val)) {
    inputVal.value = val.length > 0 ? val[0] : null
  } else {
    inputVal.value = val
  }
}
const reset = () => {
  resetValue(props.modelValue)
  if (props.readonly) {
    if (inputVal.value == null || inputVal.value.length === 0) {
      names.value = []
    } else if (Array.isArray(inputVal.value)) {
      loadItemText(inputVal.value)
    } else {
      loadItemText([inputVal.value])
    }
    refreshLabel()
  } else {
    loadDict()
  }
}
const loadDict = async () => {
  const res = await gets(props.dicId)
  if (props.filterFunc) {
    items.value = props.filterFunc(res)
  } else {
    items.value = res
  }
  refreshLabel()
}
const loadItemText = async (ids) => {
  names.value = await GetDicTextList(props.dicId, ids)
}
const refreshLabel = () => {
  if (props.source == null || props.labelField == null) {
    return
  } else if (props.readonly) {
    unref(props.source)[props.labelField] = unref(names)?.join(',')
  } else if (inputVal.value == null || inputVal.value.length === 0) {
    unref(props.source)[props.labelField] = null
  } else if (Array.isArray(inputVal.value)) {
    const list = inputVal.value
    const item = items.value.filter((c) => list.includes(c.DicValue))
    unref(props.source)[props.labelField] = joinStr(item, (c: dicItemModel) => c.DicText)
  } else {
    const item = items.value.find((c) => c.DicValue == inputVal.value)
    unref(props.source)[props.labelField] = item?.DicText
  }
}
const chooseChange = (value) => {
  inputVal.value = value
  let item
  let val = null
  if (value != null && value.length !== 0) {
    if (Array.isArray(value)) {
      item = items.value.filter((c) => value.includes(c.DicValue))
      val = props.multiple ? value : value[0]
    } else {
      item = items.value.find((c) => c.DicValue === value)
      val = props.multiple ? [value] : value
    }
  }
  refreshLabel()
  emit('update:modelValue', val)
  emit('change', val, item)
}
watch(
  () => props.dicId,
  (dic: string) => {
    if (dic) {
      reset()
    }
  },
  {
    immediate: true
  }
)
watch(
  () => props.modelValue,
  (val) => {
    resetValue(val)
    if (props.readonly) {
      reset()
    }
  },
  {
    immediate: true
  }
)
watch(
  () => props.multiple,
  (val) => {
    if (
      val &&
      props.modelValue != null &&
      Array.isArray(props.modelValue) &&
      props.modelValue.length > 1
    ) {
      resetValue(null)
    } else {
      resetValue(props.modelValue)
    }
  },
  {
    immediate: false
  }
)
watch(
  () => props.mode,
  (val) => {
    resetValue(props.modelValue)
  },
  {
    immediate: false
  }
)
</script>

<style scoped>
.itemNames {
  width: 100%;
}
.el-radio-button {
  margin-bottom: 5px;
}
.el-checkbox-button {
  margin-bottom: 5px;
}
</style>
